<template>
  <NFormItem
    class="nv-form-item"
    :path="field"
    :show-label="option.showLabel"
    :label-width="option.labelWidth"
    :label-style="mergeStyle(props.labelStyle, option.labelStyle)"
    :label-align="option.labelAlign"
    :label-placement="option.labelPlacement"
    :feedback-class="mergeClass(props.feedbackClass)"
    :feedback-style="mergeStyle(props.feedbackStyle)"
  >
    <slot v-bind="formFieldOption" :dict-data :loading />
    <template v-if="typeof option.label === 'function'" #label>
      <component :is="option.label" />
    </template>
    <template v-else #label>
      {{ option.label }}
    </template>
  </NFormItem>
</template>

<script setup lang="tsx">
import type { Component } from 'vue'
import type { RenderView } from '@/context'
import type { NvFormItemOption, NvFormMode } from '@/form/types'
import type { BaseComponentProps, CustomSlots, RowData } from '@/types'
import { NFormItem, useThemeVars } from 'naive-ui'
import { computed, markRaw } from 'vue'
import { defaultRenderView } from '@/components/render-view'
import { NV_CRUD_CONTEXT } from '@/context'
import { mergeClass, mergeStyle } from '@/utils'
import { useDict } from '@/utils/use-dict'

defineOptions({
  inheritAttrs: false,
})

const props = defineProps<Props>()

interface Props extends BaseComponentProps {
  form: RowData
  field: string
  option: NvFormItemOption
  mode?: NvFormMode
  feedbackClass?: BaseComponentProps['class']
  feedbackStyle?: BaseComponentProps['style']
  labelStyle?: BaseComponentProps['style']
}
const theme = useThemeVars()

const { loading, dictData } = useDict(props)

interface FormItemInnerOption {
  component: Component | RenderView
  fieldProps: { [key: string]: any }
  fieldSlots: CustomSlots
  renderView?: RenderView
  vModel: string
}

const formFieldOption = computed<FormItemInnerOption>(() => {
  const option = props.option

  const config = NV_CRUD_CONTEXT.getComponent(option.type || 'input', 'input')

  const { component, defaultProps, defaultSlots, config: { vModel, renderView } = {} } = config

  return {
    component: props.mode === 'view' ? markRaw(renderView || defaultRenderView) : markRaw(component),
    fieldProps: {
      ...defaultProps,
      ...option.props,
      style: mergeStyle(defaultProps?.style, option.style, option.props?.style),
      class: mergeClass(defaultProps?.class, option.class, option.props?.class),
    },
    fieldSlots: {
      ...defaultSlots,
      ...option.slots,
    },
    renderView,
    vModel: vModel || 'value',
  }
})
</script>

<style lang="scss">
.nv-form__mode-view .nv-form-item {
  height: 100%;
  border-radius: 4px;
  overflow: hidden;
  transition: background-color 0.3s;
  background-color: v-bind('theme.tableColor');
  border: 1px solid v-bind('theme.dividerColor');

  &:hover {
    background-color: v-bind('theme.tableColorHover');

    .n-form-item-label {
      background-color: unset;
    }
  }

  .n-form-item-label {
    height: 100%;
    padding: 8px 10px;
    align-items: start;
    transition: background-color 0.3s;
    color: v-bind('theme.textColor3');
    background-color: v-bind('theme.tableHeaderColor');
  }

  .n-form-item-blank {
    padding: 0 10px;
  }
}

.nv-form:not(.nv-form__mode-view) .n-form-item.n-form-item--top-labelled .n-form-item-label {
  padding-bottom: 0px;
  position: relative;
  top: 4px;
}
</style>
